/*
 * get_mp3_seconds
 *
 * 2006 by Thomas Rogg <http://thomas.cherryware.de/>
 * Copyleft but always include credits, please!
 *
 * returns the exact duration of the given MP3 file
 *
 * MP3 file can be of any MPEG version and bitrate (even variable)
 * runs on any architecture (litte and big endian)
 *
 *
 ********************************
 *
 * Taken from http://thomas.cherryware.de/download/mp3_seconds.cpp
 *
 *  Edits By Karlan Mitchell.  Same as above, just include credits.
 *  mostly to the above person who wrote 99% of this library.
 *  The main edit is when the MP3 doesn't provide the sampling rate, you can guess it.
 *
 * replaced secs += (double)samplesPerFrame / (double)samplingRate;
 * with secs += (double)samplesPerFrame / (double)((samplingRate == 0) ? (44100) : (samplingRate));
 *
 * replaced size = (samplesPerFrame * bitRate) / (8 * samplingRate) + padding;
 * with size = (samplesPerFrame * bitRate) / (8 * ((samplingRate == 0) ? (44100) : (samplingRate))) + padding;
 *
 * changed true to TRUE
 * changed .cpp to .c
 * karlanmitchell@gmail.com
 *
 */

#include <stdio.h>

double get_mp3_seconds(const char *file_name);


// Lookup tables
const int MP3_BITRATE_TABLE[2][15] = {
	{0,  8, 16, 24, 32, 40, 48, 56,  64,  80,  96, 112, 128, 144, 160},
	{0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320}
};

const int MP3_SAMPLINGRATE_TABLE[4][3] = {
	{11025, 12000,  8000},
	{    0,     0,     0},
	{22050, 24000, 16000},
	{44100, 48000, 32000}
};


// Library functions
double get_mp3_seconds(const char *file_name)
{
	char littleEndian[2] = {1, 0};
	int bitRate, samplingRate;
	int samplesPerFrame, padding;
	unsigned int header;
	int size;
	double secs = 0;

	FILE *file = fopen(file_name, "rb");
	if(!file)
		return 0;

	while(1)
	{
		// Skip to next valid header
		if(fread(&header, 4, 1, file) != 1)
			break;
		if(*(short *)littleEndian == 1)
			header =
				(header >> 24) | ((header >> 8) & 0x0000FF00) |
				((header << 8) & 0x00FF0000) | (header << 24);

		while(
			(header & 0xFFE60000) != 0xFFE20000 || (header & 0x00180000) == 0x00080000 ||
			(header & 0x0000F000) == 0x0000F000 || (header & 0x00000C00) == 0x00000C00)
		{
			// Possible reasons for random data in file: ID3 tags, variable data rate...
			header <<= 8;
			if(*(short *)littleEndian == 1)
			{
				if(fread(&header, 1, 1, file) != 1)
					break;
			}
			else
			{
				if(fread((unsigned char *)&header + 3, 1, 1, file) != 1)
					break;
			}
		}

		// Table access indicies are valid (sure about that b/c of header sanity checks)
		bitRate			= MP3_BITRATE_TABLE[(header >> 19) & 0x01][(header >> 12) & 0x0F] * 1000;
		samplingRate	= MP3_SAMPLINGRATE_TABLE[(header >> 19) & 0x03][(header >> 10) & 0x03];
		samplesPerFrame	= 576 << ((header >> 19) & 0x01);
		padding			= ((header >> 9) & 0x01) - 4;

		// bitRate == 0 => variable bit rate, no way to seek
		if(bitRate != 0)
		{
			// Sampling rate != 0 (sure about that b/c of header sanity checks)
			size = (samplesPerFrame * bitRate) / (8 * ((samplingRate == 0) ? (44100) : (samplingRate))) + padding;
			if(fseek(file, size, SEEK_CUR) != 0)
				break;
		}

		// Sampling rate != 0 (sure about that b/c of header sanity checks)
		secs += (double)samplesPerFrame / (double)((samplingRate == 0) ? (44100) : (samplingRate));
	}

	fclose(file);
	return secs;
}
